package cn.virens.common.mybatis.mapper.example.util;

import cn.virens.common.util.exception.APIException;

import java.io.Serializable;

/**
 * SQL构建器
 *
 * @author virens
 */
@SuppressWarnings("serial")
public class SQLBuidler implements Serializable {
    private final StringBuilder builder = new StringBuilder();

    public SQLBuidler(String... strArray) {
        this.append(strArray);
    }

    /**
     * 添加字符串数组
     *
     * @param strArray 字符串数组
     * @return SQL构建器
     */
    public SQLBuidler append(String... strArray) {
        for (String string : strArray) {
            this.builder.append(string);
        }

        return this;
    }

    /**
     * 添加字符串数组(添加换行符)
     *
     * @param strArray 字符串数组
     * @return SQL构建器
     */
    public SQLBuidler appendEl(String... strArray) {
        this.builder.append("\r\n");
        this.append(strArray);

        return this;
    }

    /**
     * 生成 trim 标签包装的 xml 结构
     *
     * @param prefix          前缀
     * @param prefixOverrides 前缀替换内容
     * @param content         标签中的内容
     * @return trim 标签包装的 xml 结构
     */
    public SQLBuidler trim(String prefix, String prefixOverrides, SQLSupplier content) throws APIException {
        this.append("<trim ")//
                .append("prefixOverrides=\"", prefixOverrides, "\" ")//
                .append("prefix=\"", prefix, "\" ")//
                .append(">");

        content.accept();

        this.append("</trim>");

        return this;
    }

    /**
     * 生成 trim 标签包装的 xml 结构
     *
     * @param prefix          前缀
     * @param suffix          后缀
     * @param prefixOverrides 前缀替换内容
     * @param suffixOverrides 后缀替换内容
     * @param content         标签中的内容
     * @return trim 标签包装的 xml 结构
     */
    public SQLBuidler trim(String prefix, String suffix, String prefixOverrides, String suffixOverrides, SQLSupplier content) throws APIException {
        this.append("<trim ")//
                .append("prefixOverrides=\"", prefixOverrides, "\" ")//
                .append("suffixOverrides=\"", suffixOverrides, "\" ")//
                .append("prefix=\"", prefix, "\" ")//
                .append("suffix=\"", suffix, "\" ")//
                .append(">");

        content.accept();

        this.append("</trim>");

        return this;
    }

    /**
     * 生成 trim 标签包装的 xml 结构
     *
     * @param start           SQL 前半段
     * @param prefix          前缀
     * @param suffix          后缀
     * @param prefixOverrides 前缀替换内容
     * @param suffixOverrides 后缀替换内容
     * @param content         标签中的内容
     * @return trim 标签包装的 xml 结构
     */
    public SQLBuidler trim(String start, String prefix, String suffix, String prefixOverrides, String suffixOverrides, SQLSupplier content) throws APIException {
        this.append(start, "<trim ")//
                .append("prefixOverrides=\"", prefixOverrides, "\" ")//
                .append("suffixOverrides=\"", suffixOverrides, "\" ")//
                .append("prefix=\"", prefix, "\" ")//
                .append("suffix=\"", suffix, "\" ")//
                .append(">");

        content.accept();

        this.append("</trim>");

        return this;
    }

    /**
     * 生成 foreach 标签包装的 xml 结构
     *
     * @param collection 遍历的对象
     * @param item       对象名
     * @param content    标签中的内容
     * @return foreach 标签包装的 xml 结构
     */
    public SQLBuidler foreach(String collection, String item, SQLSupplier content) throws APIException {
        this.append("<foreach ")//
                .append("collection=\"", collection, "\" ")//
                .append("item=\"", item, "\" ")//
                .append(">");

        content.accept();

        this.append("</foreach>");

        return this;
    }

    /**
     * 生成 foreach 标签包装的 xml 结构
     *
     * @param collection 遍历的对象
     * @param item       对象名
     * @param separator  连接符
     * @param content    标签中的内容
     * @return foreach 标签包装的 xml 结构
     */
    public SQLBuidler foreach(String collection, String item, String separator, SQLSupplier content) throws APIException {
        this.append("<foreach ")//
                .append("collection=\"", collection, "\" ")//
                .append("separator=\"", separator, "\" ")//
                .append("item=\"", item, "\" ")//
                .append(">");

        content.accept();

        this.append("</foreach>");

        return this;
    }

    /**
     * 生成 foreach 标签包装的 xml 结构
     *
     * @param collection 遍历的对象
     * @param item       对象名
     * @param separator  连接符
     * @param open       开始符号
     * @param close      结束符号
     * @param content    标签中的内容
     * @return foreach 标签包装的 xml 结构
     */
    public SQLBuidler foreach(String collection, String item, String separator, String open, String close, SQLSupplier content) throws APIException {
        this.append("<foreach ")//
                .append("collection=\"", collection, "\" ")//
                .append("separator=\"", separator, "\" ")//
                .append("close=\"", close, "\" ")//
                .append("open=\"", open, "\" ")//
                .append("item=\"", item, "\" ")//
                .append(">");

        content.accept();

        this.append("</foreach>");

        return this;
    }

    /**
     * 生成 foreach 标签包装的 xml 结构
     *
     * @param collection 遍历的对象
     * @param item       对象名
     * @param separator  连接符
     * @param open       开始符号
     * @param close      结束符号
     * @param index      索引名（list为索引，map为key）
     * @param content    标签中的内容
     * @return foreach 标签包装的 xml 结构
     */
    public SQLBuidler foreach(String collection, String item, String separator, String open, String close, String index, SQLSupplier content) throws APIException {
        this.append("<foreach ")//
                .append("collection=\"", collection, "\" ")//
                .append("separator=\"", separator, "\" ")//
                .append("index=\"", index, "\" ")//
                .append("close=\"", close, "\" ")//
                .append("open=\"", open, "\" ")//
                .append("item=\"", item, "\" ")//
                .append(">");

        content.accept();

        this.append("</foreach>");

        return this;
    }

    /**
     * 生成 choose 标签包装的 xml 结构
     *
     * @param content 标签中的内容
     * @return choose 标签包装的 xml 结构
     */
    public SQLBuidler choose(SQLSupplier content) throws APIException {
        this.append("<choose>");

        content.accept();

        this.append("</choose>");

        return this;
    }

    /**
     * 生成 otherwise 标签包装的 xml 结构
     *
     * @param content 标签中的内容
     * @return otherwise 标签包装的 xml 结构
     */
    public SQLBuidler chooseOther(SQLSupplier content) throws APIException {
        this.append("<otherwise>");

        content.accept();

        this.append("</otherwise>");

        return this;
    }

    /**
     * 生成 when 标签包装的 xml 结构
     *
     * @param test    when 的判断条件
     * @param content 标签中的内容
     * @return when 标签包装的 xml 结构
     */
    public SQLBuidler chooseWhen(String test, SQLSupplier content) throws APIException {
        this.append("<when ")//
                .append("test=\"", test, "\" ")//
                .append(">");

        content.accept();

        this.append("</when>");

        return this;
    }

    /**
     * 生成 set 标签包装的 xml 结构
     *
     * @param content 标签中的内容
     * @return set 标签包装的 xml 结构
     */
    public SQLBuidler set(SQLSupplier content) throws APIException {
        this.append("<set>");

        content.accept();

        this.append("</set>");

        return this;
    }

    /**
     * 生成 if 标签包装的 xml 结构
     *
     * @param test    if 的判断条件
     * @param content 标签中的内容
     * @return if 标签包装的 xml 结构
     */
    public SQLBuidler ifTest(String test, SQLSupplier content) throws APIException {
        this.append("<if ")//
                .append("test=\"", test, "\" ")//
                .append(">");

        content.accept();

        this.append("</if>");

        return this;
    }

    /**
     * 生成 if 标签包装的 xml 结构(属性为空)
     *
     * @param variable if 的判断变量
     * @param content  标签中的内容
     * @return if 标签包装的 xml 结构
     */
    public SQLBuidler ifEmpty(String variable, SQLSupplier content) throws APIException {
        return ifTest(isEmpty(variable), content);
    }

    /**
     * 生成 if 标签包装的 xml 结构(属性不为空)
     *
     * @param variable if 的判断变量
     * @param content  标签中的内容
     * @return if 标签包装的 xml 结构
     */
    public SQLBuidler ifNotEmpty(String variable, SQLSupplier content) throws APIException {
        return ifTest(isNotEmpty(variable), content);
    }

    /**
     * 生成参数验证代码
     *
     * @param variable 判断变量
     * @return
     * @throws APIException
     */
    public SQLBuidler assertNotNull(String variable) throws APIException {
        return append("${", notNull(variable), "}");
    }

    @Override
    public String toString() throws APIException {
        return builder.toString();
    }

    public static String isNotEmpty(String variable) throws APIException {
        return "@" + Util.class.getName() + "@isNotEmpty(" + variable + ")";
    }

    public static String isEmpty(String variable) throws APIException {
        return "@" + Util.class.getName() + "@isEmpty(" + variable + ")";
    }

    public static String notNull(String variable) throws APIException {
        return "@" + Util.class.getName() + "@notNull(" + variable + ")";
    }

    public static SQLBuidler of(String... strArray) {
        return new SQLBuidler(strArray);
    }

    @FunctionalInterface
    public interface SQLSupplier {
        void accept();
    }
}
